﻿using System;
using System.Collections.Generic;
using Exceptionless;
using Exceptionless.Logging;
using Exceptionless.Plugins;
using Newtonsoft.Json;
using ZilLion.Service.Core.ConfigManager.Manager;

namespace ZilLion.Service.Core.Log
{
    /// <summary>
    ///     日志组件
    /// </summary>
    public partial class DefaultLogger : ILoggerProvider
    {
        public DefaultLogger()
        {
            ZilLionConfigurationManager.GetConfigInstance<LoggerConfig>();
            InitExceptionlessClient();
        }

        #region 日志操作

        /// <summary>
        ///     Debug日志
        /// </summary>
        /// <param name="message"></param>
        /// <param name="context"></param>
        /// <param name="tags"></param>
        public void Debug(string message, object context = null, params string[] tags)
        {
            NLoggerClient?.Debug(message);
        }

        /// <summary>
        ///     记录错误日志
        /// </summary>
        /// <param name="ex"></param>
        /// <param name="context"></param>
        /// <param name="tags"></param>
        public virtual void Error(Exception ex, object context = null, params string[] tags)
        {
            if (ErrorClient != null)
            {
                var contextData =
                    new ContextData(new Dictionary<string, object> {{"errContext", context ?? new object()}});
                contextData.MarkAsUnhandledError();
                contextData.SetException(ex);
                var builder = ex.ToExceptionless(contextData, ErrorClient)
                    .AddTags(tags)
                    // 标记为关键异常
                    .MarkAsCritical()
                    .SetReferenceId(Guid.NewGuid().ToString("N"));
                builder.Submit();
            }

            else
            {
                NLoggerClient?.Error(ex);
            }
        }

        public void Info(string message, object context = null, params string[] tags)
        {
            Log(message, LogLevel.Info, context, tags);
        }

        public void Trace(string message, object context = null, params string[] tags)
        {
            Log(message, LogLevel.Trace, context, tags);
        }

        public void Warn(string message, object context = null, params string[] tags)
        {
            Log(message, LogLevel.Warn, context, tags);
        }

        /// <summary>
        ///     记录Message日志
        /// </summary>
        /// <param name="message"></param>
        /// <param name="level"></param>
        /// <param name="context"></param>
        /// <param name="tags"></param>
        public virtual void Log(string message, LogLevel level, object context = null, params string[] tags)
        {
            string nlogmessage;
            try
            {
                nlogmessage =
                    $"{message}{Environment.NewLine}{(context == null ? string.Empty : JsonConvert.SerializeObject(context))}";
            }
            catch (Exception)
            {
                nlogmessage = message;
            }
            if (level >= LogLevel.Warn)
            {
                SendMessageToExceptionless(message, level, context, tags);
            }
            else
            {
                if (ZilLionConfigurationManager.GetConfigInstance<LoggerConfig>().SendTraceMessage)
                {
                    SendMessageToExceptionless(message, level, context, tags);
                }
            }

            NLoggerClient?.Log(CastToNlogLogLevel(level), nlogmessage);
        }

        private void SendMessageToExceptionless(string message, LogLevel level, object context = null,
            params string[] tags)
        {
            if (MessageClient != null)
            {
                var bulider =
                    MessageClient.CreateLog(message, level)
                        .SetReferenceId(Guid.NewGuid().ToString("N"))
                        .AddTags(tags);
                if (context != null)
                    bulider.AddObject(context);
                bulider.Submit();
            }
        }

        protected NLog.LogLevel CastToNlogLogLevel(LogLevel level)
        {
            if (level == LogLevel.Debug)
                return NLog.LogLevel.Debug;
            if (level == LogLevel.Trace)
                return NLog.LogLevel.Trace;
            if (level == LogLevel.Info)
                return NLog.LogLevel.Info;
            if (level == LogLevel.Error)
                return NLog.LogLevel.Error;
            //最后如果找不到对应的LogLevel 则返回Debug
            return level == LogLevel.Warn ? NLog.LogLevel.Warn : NLog.LogLevel.Debug;
        }

        #endregion
    }
}